package controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JDialog;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import util.HibernateUtil;
import view.AddUserPage;
import view.EditUserPage;
import view.SearchUserPage;
import bean.User;

import com.mysql.jdbc.StringUtils;

import dto.LogonDTO;
import dto.UserDTO;

public class UserController {

	private AddUserPage addUser;
	private SearchUserPage searchUser;
	private EditUserPage editUser;
	private UserDTO dto;

	private String userName;
	private String errorMessage;

	void addUser(LogonDTO logonDTO) {

		userName = logonDTO.getUserName();

		addUser = new AddUserPage(logonDTO);
		addUser.addAddUserButtonListener(new AddUserListener());

		addUser.setModal(true);
		addUser.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		addUser.setVisible(true);

	}

	void searchUser(LogonDTO logonDTO) {

		userName = logonDTO.getUserName();

		searchUser = new SearchUserPage(logonDTO);
		searchUser.addSearchUserButtonListener(new SearchUserListener());

		searchUser.setModal(true);
		searchUser.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		searchUser.setVisible(true);

	}

	void editUser(LogonDTO logonDTO, UserDTO userDTO) {

		userName = logonDTO.getUserName();

		editUser = new EditUserPage(logonDTO, userDTO);
		editUser.addUpdateUserButtonListener(new EditUserListener());
		editUser.setModal(true);
		editUser.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		editUser.setVisible(true);

	}

	class AddUserListener implements ActionListener {

		public void actionPerformed(ActionEvent arg0) {
			dto = addUser.getUserDTO();

			if (validateUserEntry("ADD")) {
				addUserToDB();
				addUser.displayMessage("Member \"" + dto.getUserId()
						+ "\" has been added.");
				addUser.clearFields();
			} else {
				addUser.displayMessage(errorMessage);
			}
		}
	}

	class SearchUserListener implements ActionListener {

		public void actionPerformed(ActionEvent arg0) {
			dto = searchUser.getUserDTO();

			List<UserDTO> users = new ArrayList<UserDTO>();
			List<User> searchResult = searchDatabase();

			for (User user : searchResult) {
				UserDTO userDTO = new UserDTO();

				userDTO.setUserId(user.getId());
				userDTO.setUserName(user.getUserName());
				userDTO.setAccessLevel(user.getLevel());

				users.add(userDTO);
			}

			searchUser.setSearchedUsers(users);
			searchUser.reDrawThis(new ActionListener() {

				public void actionPerformed(ActionEvent arg0) {
					int index = Integer.parseInt(arg0.getActionCommand());

					editUser(searchUser.getLogonDTO(), searchUser
							.getSearchedUsers().get(index));

				}
			}, new DeleteUserListener());

			searchUser.displayMessage("Found " + users.size() + " match(es).");
		}
	}

	class EditUserListener implements ActionListener {

		public void actionPerformed(ActionEvent arg0) {
			dto = editUser.getUserDTO();

			if (validateUserEntry("EDIT")) {
				editUserInDB();
				editUser.displayMessage("\"" + dto.getUserId()
						+ "\" has been updated.");
			} else {
				editUser.displayMessage(errorMessage);
			}
		}
	}

	class DeleteUserListener implements ActionListener {

		public void actionPerformed(ActionEvent arg0) {
			int index = Integer.parseInt(arg0.getActionCommand());
			UserDTO selectedUserToDelete = searchUser.getSearchedUsers().get(
					index);

			String userStr = "[" + selectedUserToDelete.getUserId() + "]"
					+ selectedUserToDelete.getUserName();
			int choice = searchUser.showConfirmDialog(userStr);

			if (choice == 0) {
				deleteUserInDB(selectedUserToDelete);

				searchUser.getSearchedUsers().remove(selectedUserToDelete);
				searchUser.reDrawThis(new ActionListener() {

					public void actionPerformed(ActionEvent arg0) {
						int index = Integer.parseInt(arg0.getActionCommand());

						editUser(searchUser.getLogonDTO(), searchUser
								.getSearchedUsers().get(index));
					}
				}, new DeleteUserListener());
				searchUser.displayMessage(userStr + " deleted.");
			}
		}
	}

	private boolean validateUserEntry(String mode) {
		boolean isValid = true;

		if (StringUtils.isNullOrEmpty(dto.getUserName())) {
			errorMessage = "Member's name should not be empty.";
			isValid = false;
		} else if (StringUtils.isNullOrEmpty(dto.getUserId())) {
			errorMessage = "Member's username should not be empty.";
			isValid = false;
		} else if ("ADD".equals(mode)
				&& StringUtils.isNullOrEmpty(dto.getPassword())) {
			errorMessage = "Password field should not be empty.";
			isValid = false;
		} else if ("ADD".equals(mode) && fetchUserById(dto.getUserId()) != null) {
			errorMessage = "Member " + dto.getUserId() + " already exists.";
			isValid = false;
		}

		return isValid;
	}

	private void addUserToDB() {
		// TODO other User's attribute, not to be included anymore?

		User userBean = new User();

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();

		userBean.setId(dto.getUserId());
		userBean.setUserName(dto.getUserName());
		userBean.setPassword(dto.getPassword());
		userBean.setLevel(dto.getAccessLevel());
		userBean.setEditedBy(userName);
		userBean.setEditedDate(getCurrentTime());

		Transaction transaction = session.beginTransaction();
		session.save(userBean);
		transaction.commit();
	}

	private List<User> searchDatabase() {

		List<User> searchResult = new ArrayList<User>();

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();

		Query query = session.createQuery(" FROM User WHERE id LIKE '%"
				+ dto.getUserId() + "%' OR userName LIKE '%" + dto.getUserId()
				+ "%'");

		List userList = query.list();
		if (!userList.isEmpty()) {
			for (int i = 0; i < userList.size(); i++) {
				User user = (User) query.list().get(i);
				searchResult.add(user);
			}
		}

		return searchResult;
	}

	private void editUserInDB() {

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();

		User userBean = fetchUserById(dto.getUserId());

		userBean.setUserName(dto.getUserName());
		userBean.setLevel(dto.getAccessLevel());
		userBean.setEditedBy(userName);
		userBean.setEditedDate(getCurrentTime());

		Transaction transaction = session.beginTransaction();
		session.saveOrUpdate(userBean);
		transaction.commit();
	}

	private void deleteUserInDB(UserDTO userDTO) {

		User userBean = null;

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();

		Query query = session.createQuery(" FROM User WHERE id = '"
				+ userDTO.getUserId() + "'");

		if (!query.list().isEmpty()) {
			userBean = (User) query.list().get(0);

			Transaction transaction = session.beginTransaction();
			session.delete(userBean);
			transaction.commit();
		}
	}

	private User fetchUserById(String userId) {
		User user = null;

		SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
		Session session = sessionFactory.openSession();

		Query query = session.createQuery(" FROM User WHERE id = '" + userId
				+ "'");

		if (!query.list().isEmpty()) {
			user = (User) query.list().get(0);
		}

		return user;
	}

	private Timestamp getCurrentTime() {
		java.util.Date date = new java.util.Date(System.currentTimeMillis());
		java.sql.Timestamp timestamp = new java.sql.Timestamp(date.getTime());

		return timestamp;
	}

}
